home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / glibc-1.09 / glibc-1 / glibc-1.09.1 / stdio / vfprintf.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-09  |  14.2 KB  |  684 lines

  1. /* Copyright (C) 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <localeinfo.h>
  21. #include <ctype.h>
  22. #include <errno.h>
  23. #include <float.h>
  24. #include <limits.h>
  25. #include <math.h>
  26. #include <stdarg.h>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30. #include <printf.h>
  31. #include <assert.h>
  32. #include "_itoa.h"
  33.  
  34.  
  35. /* If it's an unbuffered stream that we provided
  36.    temporary buffering for, remove that buffering.  */
  37. #define    RETURN(x)                                  \
  38.   do                                          \
  39.     {                                          \
  40.       done = (x);                                  \
  41.       goto do_return;                                  \
  42.     } while (0)
  43.  
  44. #define    outchar(x)                                  \
  45.   do                                          \
  46.     {                                          \
  47.       register CONST int outc = (x);                          \
  48.       if (putc(outc, s) == EOF)                              \
  49.     RETURN(-1);                                  \
  50.       else                                      \
  51.     ++done;                                      \
  52.     } while (0)
  53.  
  54. /* Cast the next arg, of type ARGTYPE, into CASTTYPE, and put it in VAR.  */
  55. #define    castarg(var, argtype, casttype) \
  56.   var = (casttype) va_arg(args, argtype)
  57. /* Get the next arg, of type TYPE, and put it in VAR.  */
  58. #define    nextarg(var, type)    castarg(var, type, type)
  59.  
  60. static printf_function printf_unknown;
  61.  
  62. extern printf_function **__printf_function_table;
  63.  
  64. #ifdef    __GNUC__
  65. #define    HAVE_LONGLONG
  66. #define    LONGLONG    long long
  67. #else
  68. #define    LONGLONG    long
  69. #endif
  70.  
  71.  
  72. int
  73. DEFUN(vfprintf, (s, format, args),
  74.       register FILE *s AND CONST char *format AND va_list args)
  75. {
  76.   /* Pointer into the format string.  */
  77.   register CONST char *f;
  78.  
  79.   /* Number of characters written.  */
  80.   register size_t done = 0;
  81.  
  82.   /* Nonzero we're providing buffering.  */
  83.   char our_buffer;
  84.   /* Temporary buffer for unbuffered streams.  */
  85.   char temporary_buffer[BUFSIZ];
  86.  
  87.   if (!__validfp(s) || !s->__mode.__write || format == NULL)
  88.     {
  89.       errno = EINVAL;
  90.       return -1;
  91.     }
  92.  
  93.   if (!s->__seen)
  94.     {
  95.       if (__flshfp(s, EOF) == EOF)
  96.     return EOF;
  97.     }
  98.  
  99.   our_buffer = s->__buffer == NULL;
  100.   if (our_buffer)
  101.     {
  102.       /* If it's an unbuffered stream, buffer it
  103.      at least inside this function call.  */
  104.       s->__bufp = s->__buffer = temporary_buffer;
  105.       s->__bufsize = sizeof(temporary_buffer);
  106.       s->__put_limit = s->__buffer + s->__bufsize;
  107.       s->__get_limit = s->__buffer;
  108.     }
  109.  
  110.   /* Reset multibyte characters to their initial state.  */
  111.   (void) mblen((char *) NULL, 0);
  112.  
  113.   f = format;
  114.   while (*f != '\0')
  115.     {
  116.       /* Type modifiers.  */
  117.       char is_short, is_long, is_long_double;
  118. #ifdef    HAVE_LONGLONG
  119.       /* We use the `L' modifier for `long long int'.  */
  120. #define    is_longlong    is_long_double
  121. #else
  122. #define    is_longlong    0
  123. #endif
  124.       /* Format spec modifiers.  */
  125.       char space, showsign, left, alt;
  126.  
  127.       /* Padding character: ' ' or '0'.  */
  128.       char pad;
  129.       /* Width of a field.  */
  130.       register int width;
  131.       /* Precision of a field.  */
  132.       int prec;
  133.  
  134.       /* Decimal integer is negative.  */
  135.       char is_neg;
  136.  
  137.       /* Current character of the format.  */
  138.       char fc;
  139.  
  140.       /* Base of a number to be written.  */
  141.       int base;
  142.       /* Integral values to be written.  */
  143.       unsigned LONGLONG int num;
  144.       LONGLONG int signed_num;
  145.  
  146.       /* String to be written.  */
  147.       CONST char *str;
  148.       char unknown_error[256];    /* Buffer sometimes used by %m.  */
  149.  
  150.       /* Auxiliary function to do output.  */
  151.       printf_function *function;
  152.  
  153.       if (!isascii(*f))
  154.     {
  155.       /* Non-ASCII, may be a multibyte.  */
  156.       int len = mblen(f, strlen(f));
  157.       if (len > 0)
  158.         {
  159.           while (len-- > 0)
  160.         outchar(*f++);
  161.           continue;
  162.         }
  163.     }
  164.  
  165.       if (*f != '%')
  166.     {
  167.       /* This isn't a format spec, so write
  168.          everything out until the next one.  */
  169.       CONST char *next = strchr(f + 1, '%');
  170.       if (next == NULL)
  171.         next = strchr(f + 1, '\0');
  172.       if (next - f > 20)
  173.         {
  174.           size_t written = fwrite((PTR) f, 1, next - f, s);
  175.           done += written;
  176.           if (written != next - f)
  177.         break;
  178.           f += written;
  179.         }
  180.       else
  181.         while (f < next)
  182.           outchar(*f++);
  183.       continue;
  184.     }
  185.  
  186.       ++f;
  187.  
  188.       /* Check for "%%".  Note that although the ANSI standard lists
  189.      '%' as a conversion specifier, it says "The complete format
  190.      specification shall be `%%'," so we can avoid all the width
  191.      and precision processing.  */
  192.       if (*f == '%')
  193.     {
  194.       ++f;
  195.       outchar('%');
  196.       continue;
  197.     }
  198.  
  199.       /* Check for spec modifiers.  */
  200.       space = showsign = left = alt = 0;
  201.       pad = ' ';
  202.       while (*f == ' ' || *f == '+' || *f == '-' || *f == '#' || *f == '0')
  203.     switch (*f++)
  204.       {
  205.       case ' ':
  206.         /* Output a space in place of a sign, when there is no sign.  */
  207.         space = 1;
  208.         break;
  209.       case '+':
  210.         /* Always output + or - for numbers.  */
  211.         showsign = 1;
  212.         break;
  213.       case '-':
  214.         /* Left-justify things.  */
  215.         left = 1;
  216.         break;
  217.       case '#':
  218.         /* Use the "alternate form":
  219.            Hex has 0x or 0X, FP always has a decimal point.  */
  220.         alt = 1;
  221.         break;
  222.       case '0':
  223.         /* Pad with 0s.  */
  224.         pad = '0';
  225.         break;
  226.       }
  227.       if (left)
  228.     pad = ' ';
  229.  
  230.       /* Get the field width.  */
  231.       width = 0;
  232.       if (*f == '*')
  233.     {
  234.       /* The field width is given in an argument.
  235.          A negative field width indicates left justification.  */
  236.       nextarg(width, int);
  237.       if (width < 0)
  238.         {
  239.           width = - width;
  240.           left = 1;
  241.         }
  242.       ++f;
  243.     }
  244.       else
  245.     while (isdigit(*f))
  246.       {
  247.         width *= 10;
  248.         width += *f++ - '0';
  249.       }
  250.  
  251.       /* Get the precision.  */
  252.       /* -1 means none given; 0 means explicit 0.  */
  253.       prec = -1;
  254.       if (*f == '.')
  255.     {
  256.       ++f;
  257.       if (*f == '*')
  258.         {
  259.           /* The precision is given in an argument.  */
  260.           nextarg(prec, int);
  261.           /* Avoid idiocy.  */
  262.           if (prec < 0)
  263.         prec = -1;
  264.           ++f;
  265.         }
  266.       else if (isdigit(*f))
  267.         {
  268.           prec = 0;
  269.           while (*f != '\0' && isdigit(*f))
  270.         {
  271.           prec *= 10;
  272.           prec += *f++ - '0';
  273.         }
  274.         }
  275.     }
  276.  
  277.       /* Check for type modifiers.  */
  278.       is_short = is_long = is_long_double = 0;
  279.       while (*f == 'h' || *f == 'l' || *f == 'L' || *f == 'q')
  280.     switch (*f++)
  281.       {
  282.       case 'h':
  283.         /* int's are short int's.  */
  284.         is_short = 1;
  285.         break;
  286.       case 'l':
  287. #ifdef    HAVE_LONGLONG
  288.         if (is_long)
  289.           /* A double `l' is equivalent to an `L'.  */
  290.           is_longlong = 1;
  291.         else
  292. #endif
  293.           /* int's are long int's.  */
  294.           is_long = 1;
  295.         break;
  296.       case 'L':
  297.         /* double's are long double's, and int's are long long int's.  */
  298.         is_long_double = 1;
  299.         break;
  300.  
  301.       case 'Z':
  302.         /* int's are size_t's.  */
  303. #ifdef    HAVE_LONGLONG
  304.         assert (sizeof(size_t) <= sizeof(unsigned long long int));
  305.         is_longlong = sizeof(size_t) > sizeof(unsigned long int);
  306. #endif
  307.         is_long = sizeof(size_t) > sizeof(unsigned int);
  308.         break;
  309.  
  310.       case 'q':
  311.         /* 4.4 uses this for long long.  */
  312. #ifdef    HAVE_LONGLONG
  313.         is_longlong = 1;
  314. #else
  315.         is_long = 1;
  316. #endif
  317.         break;
  318.       }
  319.  
  320.       /* Format specification.  */
  321.       fc = *f++;
  322.       function = (__printf_function_table == NULL ? NULL :
  323.           __printf_function_table[fc]);
  324.       if (function == NULL)
  325.     switch (fc)
  326.       {
  327.       case 'i':
  328.       case 'd':
  329.         /* Decimal integer.  */
  330.         base = 10;
  331.         if (is_longlong)
  332.           nextarg(signed_num, LONGLONG int);
  333.         else if (is_long)
  334.           nextarg(signed_num, long int);
  335.         else if (!is_short)
  336.           castarg(signed_num, int, long int);
  337.         else
  338.           castarg(signed_num, int, short int);
  339.  
  340.         is_neg = signed_num < 0;
  341.         num = is_neg ? (- signed_num) : signed_num;
  342.         goto number;
  343.  
  344.       case 'u':
  345.         /* Decimal unsigned integer.  */
  346.         base = 10;
  347.         goto unsigned_number;
  348.  
  349.       case 'o':
  350.         /* Octal unsigned integer.  */
  351.         base = 8;
  352.         goto unsigned_number;
  353.  
  354.       case 'X':
  355.         /* Hexadecimal unsigned integer.  */
  356.       case 'x':
  357.         /* Hex with lower-case digits.  */
  358.  
  359.         base = 16;
  360.  
  361.       unsigned_number:
  362.         /* Unsigned number of base BASE.  */
  363.  
  364.         if (is_longlong)
  365.           castarg(num, LONGLONG int, unsigned LONGLONG int);
  366.         else if (is_long)
  367.           castarg(num, long int, unsigned long int);
  368.         else if (!is_short)
  369.           castarg(num, int, unsigned int);
  370.         else
  371.           castarg(num, int, unsigned short int);
  372.  
  373.         /* ANSI only specifies the `+' and
  374.            ` ' flags for signed conversions.  */
  375.         is_neg = showsign = space = 0;
  376.  
  377.       number:
  378.         /* Number of base BASE.  */
  379.         {
  380.           char work[BUFSIZ];
  381.           char *CONST workend = &work[sizeof(work) - 1];
  382.           register char *w;
  383.  
  384.           /* Supply a default precision if none was given.  */
  385.           if (prec == -1)
  386.         prec = 1;
  387.  
  388.           /* Put the number in WORK.  */
  389.           w = _itoa (num, workend + 1, base, fc == 'X') - 1;
  390.           width -= workend - w;
  391.           prec -= workend - w;
  392.  
  393.           if (alt && base == 8 && prec <= 0)
  394.         {
  395.           *w-- = '0';
  396.           --width;
  397.         }
  398.  
  399.           if (prec > 0)
  400.         {
  401.           width -= prec;
  402.           while (prec-- > 0)
  403.             *w-- = '0';
  404.         }
  405.  
  406.           if (alt && base == 16)
  407.         width -= 2;
  408.  
  409.           if (is_neg || showsign || space)
  410.         --width;
  411.  
  412.           if (!left && pad == ' ')
  413.         while (width-- > 0)
  414.           outchar(' ');
  415.  
  416.           if (is_neg)
  417.         outchar('-');
  418.           else if (showsign)
  419.         outchar('+');
  420.           else if (space)
  421.         outchar(' ');
  422.  
  423.           if (alt && base == 16)
  424.         {
  425.           outchar ('0');
  426.           outchar (fc);
  427.         }
  428.  
  429.           if (!left && pad == '0')
  430.         while (width-- > 0)
  431.           outchar('0');
  432.  
  433.           /* Write the number.  */
  434.           while (++w <= workend)
  435.         outchar(*w);
  436.  
  437.           if (left)
  438.         while (width-- > 0)
  439.           outchar(' ');
  440.         }
  441.         break;
  442.  
  443.       case 'e':
  444.       case 'E':
  445.       case 'f':
  446.       case 'g':
  447.       case 'G':
  448.         {
  449.           /* Floating-point number.  */
  450.           extern printf_function __printf_fp;
  451.           function = __printf_fp;
  452.           goto use_function;
  453.         }
  454.  
  455.       case 'c':
  456.         /* Character.  */
  457.         nextarg(num, int);
  458.         if (!left)
  459.           while (--width > 0)
  460.         outchar(' ');
  461.         outchar((unsigned char) num);
  462.         if (left)
  463.           while (--width > 0)
  464.         outchar(' ');
  465.         break;
  466.  
  467.       case 's':
  468.         {
  469.           static CONST char null[] = "(null)";
  470.           size_t len;
  471.  
  472.           nextarg(str, CONST char *);
  473.  
  474.         string:
  475.  
  476.           if (str == NULL)
  477.         /* Write "(null)" if there's space.  */
  478.         if (prec == -1 || prec >= (int) sizeof(null) - 1)
  479.           {
  480.             str = null;
  481.             len = sizeof(null) - 1;
  482.           }
  483.         else
  484.           {
  485.             str = "";
  486.             len = 0;
  487.           }
  488.           else
  489.         len = strlen(str);
  490.  
  491.           if (prec != -1 && (size_t) prec < len)
  492.         len = prec;
  493.           width -= len;
  494.  
  495.           if (!left)
  496.         while (width-- > 0)
  497.           outchar(' ');
  498.           if (len < 20)
  499.         while (len-- > 0)
  500.           outchar(*str++);
  501.           else
  502.         if (fwrite(str, 1, len, s) != len)
  503.           RETURN(-1);
  504.         else
  505.           done += len;
  506.           if (left)
  507.         while (width-- > 0)
  508.           outchar(' ');
  509.         }
  510.         break;
  511.  
  512.       case 'p':
  513.         /* Generic pointer.  */
  514.         {
  515.           CONST PTR ptr;
  516.           nextarg(ptr, CONST PTR);
  517.           if (ptr != NULL)
  518.         {
  519.           /* If the pointer is not NULL, write it as a %#x spec.  */
  520.           base = 16;
  521.           fc = 'x';
  522.           alt = 1;
  523.           num = (unsigned LONGLONG int) (unsigned long int) ptr;
  524.           is_neg = 0;
  525.           goto number;
  526.         }
  527.           else
  528.         {
  529.           /* Write "(nil)" for a nil pointer.  */
  530.           static CONST char nil[] = "(nil)";
  531.           register CONST char *p;
  532.  
  533.           width -= sizeof (nil) - 1;
  534.           if (!left)
  535.             while (width-- > 0)
  536.               outchar (' ');
  537.           for (p = nil; *p != '\0'; ++p)
  538.             outchar (*p);
  539.           if (left)
  540.             while (width-- > 0)
  541.               outchar (' ');
  542.         }
  543.         }
  544.         break;
  545.  
  546.       case 'n':
  547.         /* Answer the count of characters written.  */
  548.         if (is_longlong)
  549.           {
  550.         LONGLONG int *p;
  551.         nextarg(p, LONGLONG int *);
  552.         *p = done;
  553.           }
  554.         else if (is_long)
  555.           {
  556.         long int *p;
  557.         nextarg(p, long int *);
  558.         *p = done;
  559.           }
  560.         else if (!is_short)
  561.           {
  562.         int *p;
  563.         nextarg(p, int *);
  564.         *p = done;
  565.           }
  566.         else
  567.           {
  568.         short int *p;
  569.         nextarg(p, short int *);
  570.         *p = done;
  571.           }
  572.         break;
  573.  
  574.       case 'm':
  575. #ifndef HAVE_GNU_LD
  576. #define _sys_errlist sys_errlist
  577. #define _sys_nerr sys_nerr
  578. #endif
  579.  
  580.         if (errno < 0 || errno > _sys_nerr)
  581.           {
  582.         sprintf (unknown_error, "Unknown error %d", errno);
  583.         str = unknown_error;
  584.           }
  585.         else
  586.           str = _sys_errlist[errno];
  587.         goto string;
  588.  
  589.       default:
  590.         /* Unrecognized format specifier.  */
  591.         function = printf_unknown;
  592.         goto use_function;
  593.       }
  594.       else
  595.       use_function:
  596.     {
  597.       int function_done;
  598.       struct printf_info info;
  599.  
  600.       info.prec = prec;
  601.       info.width = width;
  602.       info.spec = fc;
  603.       info.is_long_double = is_long_double;
  604.       info.is_short = is_short;
  605.       info.is_long = is_long;
  606.       info.alt = alt;
  607.       info.space = space;
  608.       info.left = left;
  609.       info.showsign = showsign;
  610.       info.pad = pad;
  611.  
  612.       function_done = (*function)(s, &info, &args);
  613.       if (function_done < 0)
  614.         RETURN(-1);
  615.  
  616.       done += function_done;
  617.     }
  618.     }
  619.  
  620.  do_return:;
  621.   if (our_buffer)
  622.     {
  623.       if (fflush(s) == EOF)
  624.     return -1;
  625.       s->__buffer = s->__bufp = s->__get_limit = s->__put_limit = NULL;
  626.       s->__bufsize = 0;
  627.     }
  628.   return done;
  629. }
  630.  
  631.  
  632. #undef    RETURN
  633. #define    RETURN    return
  634.  
  635. static int
  636. DEFUN(printf_unknown, (s, type, info, arg),
  637.       FILE *s AND CONST struct printf_info *info AND va_list *arg)
  638. {
  639.   int done = 0;
  640.   char work[BUFSIZ];
  641.   char *CONST workend = &work[sizeof(work) - 1];
  642.   register char *w;
  643.   register int prec = info->prec, width = info->width;
  644.  
  645.   outchar('%');
  646.  
  647.   if (info->alt)
  648.     outchar('#');
  649.   if (info->showsign)
  650.     outchar('+');
  651.   else if (info->space)
  652.     outchar(' ');
  653.   if (info->left)
  654.     outchar('-');
  655.   if (info->pad == '0')
  656.     outchar('0');
  657.  
  658.   w = workend;
  659.   while (width > 0)
  660.     {
  661.       *w-- = '0' + (width % 10);
  662.       width /= 10;
  663.     }
  664.   while (++w <= workend)
  665.     outchar(*w);
  666.  
  667.   if (info->prec != -1)
  668.     {
  669.       outchar('.');
  670.       w = workend;
  671.       while (prec > 0)
  672.     {
  673.       *w-- = '0' + (prec % 10);
  674.       prec /= 10;
  675.     }
  676.       while (++w <= workend)
  677.     outchar(*w);
  678.     }
  679.  
  680.   outchar(info->spec);
  681.  
  682.   return done;
  683. }
  684.